#pragma once

#include <stdio.h>
#include <pthread.h>
#include <queue>
typedef void (*fuction)(int);

class Data
{
    public:
        Data()
        {}
        
        ~Data()
        {}
        
        Data(int data, fuction fun){
            fun_ = fun;
            data_ = data;
        }
    public:
        void Run(){
            this->fun_(data_);
        }

        int Get()
        {
            return data_;
        }
    private:
        int data_;
        fuction fun_;
};


//封装线程池中线程安全的队列
//线程池中的线程如何优雅的退出？
//应该在队列为空，即资源全部处理完毕后将所有的线程退出
class SafQue
{
    public:
        SafQue()
        {
            capacity_ = 3;
            pthread_mutex_init(&mutex_, NULL);
            pthread_cond_init(&pro_, NULL);
            pthread_cond_init(&cons_, NULL);
        }

        ~SafQue()
        {
            pthread_mutex_destroy(&mutex_);
            pthread_cond_destroy(&cons_);
            pthread_cond_destroy(&pro_);
        }
    public:
       void Push(Data& data)
       {
           pthread_mutex_lock(&mutex_);
           while(que_.size() >= capacity_){
               pthread_cond_wait(&pro_, &mutex_);
           }
           que_.push(data);

           pthread_mutex_unlock(&mutex_);
           pthread_cond_signal(&cons_);

       }

       Data Pop(int flag)
       {
           pthread_mutex_lock(&mutex_);
           while(que_.empty()){
               if(flag){
                   pthread_mutex_unlock(&mutex_);
                   pthread_exit(NULL);
               }
               pthread_cond_wait(&cons_, &mutex_);
           }

           Data ret = que_.front();
           que_.pop();

           pthread_mutex_unlock(&mutex_);
           pthread_cond_signal(&pro_);

           return ret;
       }

       void Broadcase()
       {
           pthread_cond_broadcast(&cons_);
       }
    private:
        std::queue<Data> que_;
        size_t capacity_;
        pthread_mutex_t mutex_;
        pthread_cond_t pro_;
        pthread_cond_t cons_;
};


class Pool
{
    public:
        Pool()
        {

        }

        ~Pool()
        {
            delete que_;
        }
    public:
       int init_pool(int thread_size)
       {
            que_ = new SafQue;
            thread_size_ = thread_size;
            exit_ = 0;
            //期望在线程池中创建size个工作线程
            for(size_t i = 0; i < thread_size_; ++i){
                pthread_t pid;
                int ret = pthread_create(&pid, NULL, work_thread, this);
                if(ret != 0){
                    thread_size_--;
                }
            }

            if(thread_size_ <= 0){
                return -1;
            }

            return 0;
       }
        
       //线程入口函数只能使用静态，不然默认会传this指针
       static void* work_thread(void* arg)
       {
           pthread_detach(pthread_self());
           Pool* pl = (Pool*) arg;
           while(1)
           {
               Data data = pl->que_->Pop(pl->exit_);
               data.Run();
           }
           return NULL;
       }

       void Push(Data& data)
       {
           que_->Push(data);
       }

       void pool_exit()
       {
            exit_ = 1;
            que_->Broadcase(); 
       }
    private:
        SafQue* que_;
        size_t thread_size_;
        //线程如何优雅的推出
        int exit_;
};
